=begin pod

=TITLE class Seq

=SUBTITLE An iterable, lazy sequence of values

    class Seq is Cool does Iterable does PositionalBindFailover { }

A C<Seq> represents anything that can lazily produce a sequence of values. A
C<Seq> is born in a state where iterating it will consume the values. However,
calling .cache on a Seq will return a List that is still lazy, but stores the
generated values for later access. The same is true when assigning a Seq to an
array.

A typical use case is L<method C<lines> in C<IO::Handle>|/type/IO::Handle#method_lines>,
which could use a lot of memory if it stored all the lines read from the
file. So

    =begin code
    for open('README.md').lines -> $line {
        say $line;
    }
    =end code

won't keep all lines from the file in memory.

This implies that you cannot iterate the same C<Seq> object twice (otherwise
it couldn't throw away old values), so this dies:

    my @a = 1, 2, 3;
    my @b = <a b c>;
    my \c = @a Z=> @b;
    .say for c;
    .say for c; # fails
    CATCH { default { put .^name, ': ', .Str } };
    # OUTPUT: «X::Seq::Consumed: This Seq has already been iterated, and its values consumed
    # (you might solve this by adding .cache on usages of the Seq, or
    # by assigning the Seq into an array)»

A high-level construct to generate a C<Seq> is C<gather/take>, as well as many
built-in methods like C<map> and C<grep>, low-level constructors to create a
Seq from an iterator or from looping constructs are available too.

B<Caution:> No program should ever assume a C<Seq> may only be iterated once
even if not cached by the program. Caching is a volatile state exposed to the
developer as an optimization. The C<Seq> may become cached by many operations,
including calling C<perl> on the C<Seq> (if called prior to a non-cached
iteration). If a program assumes a Seq can only iterate once, but then is
later changed to call one of these operations during the loop, that assumption
will fail.

=head1 Methods

=head2 method new

    method new(Iterator:D $iter --> Seq:D)

Creates a new C<Seq> object from the iterator passed as the single argument.

=head2 method iterator

    method iterator(Seq:D: --> Iterator:D)

Returns the underlying iterator, and marks the invocant as consumed.
If called on an already consumed sequence, throws an error of type
L<X::Seq::Consumed>.

=head2 method is-lazy

    method is-lazy(Seq:D: --> Bool:D)

Returns C<True> if the sequence is lazy and potentially infinite, and C<False>
otherwise.
If called on an already consumed sequence, throws an error of type
L<X::Seq::Consumed>.

=head2 method eager

    method eager(Seq:D: --> List:D)

Returns an eagerly evaluated L<List|/type/List> based on the invocant
sequence, and marks it as consumed.
If called on an already consumed sequence, throws an error of type
L<X::Seq::Consumed>.

    my $s = lazy 1..5;

    say $s.is-lazy; # OUTPUT: «True␤»
    say $s.eager;   # OUTPUT: «(1 2 3 4 5)␤»

    say $s.eager;
    CATCH {
        when X::Seq::Consumed {
            say 'Throws exception if already consumed';
        }
    }
    # OUTPUT: «Throws exception if already consumed␤»


=head2 method from-loop

    multi method from-loop(&body --> Seq:D)
    multi method from-loop(&body, &cond, :$repeat --> Seq:D)
    multi method from-loop(&body, &cond, &afterward --> Seq:D)

These methods create new C<Seq>-based callbacks.

The first form produces an infinite C<Seq> by calling C<&body> each time a new
element is requested, using the return value from C<&body> as the item. This
emulates (or implements) a C<loop { body }> construct.

The second form calls C<&cond> before each call to C<&body>, and terminates
the sequence if C<&cond> returns a false value. If C<$repeat> is set to a true
value, the first call to C<&cond> is omitted, and C<&body> called right away.
This emulates (or implements) C<while cond { body }> and
C<repeat { body } while cond> loops.

The third form enables C-style looping by calling a third callback,
C<&afterward>, after each call to C<&body>.

=head2 method skip

Defined As:

    multi method skip(Int() $n = 1 --> Seq)

Returns a Seq containing whatever is left of the invocant after
throwing away C<$n> of the next available values. Negative values of
C<$n> count as 0.  Also can take a WhateverCode to indicate how many values
to skip from the end.  Will block on lazy Seqs until the requested
number of values have been discarded.

    say (1..5).map({$_}).skip;      # OUTPUT: «(2,3,4,5)␤»
    say (1..5).map({$_}).skip(3);   # OUTPUT: «(4,5)␤»
    say (1..5).map({$_}).skip(5);   # OUTPUT: «()␤»
    say (1..5).map({$_}).skip(-1);  # OUTPUT: «(1,2,3,4,5)␤»
    say (1..5).map({$_}).skip(*-3); # OUTPUT: «(3,4,5)␤»

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
